<?php

namespace app\common\services;

use RuntimeException;

class DependencyCheck
{
    /**
     * @var array 检查条目
     */
    protected $items = [];

    protected $operations = [
        'func_exist',
        'class_exist',
        'ext_exist',
        'file_exist',
        'can_read',
        'can_write',
        'db',
    ];

    public function __construct($items)
    {
        foreach ($items as $name => $item) {
            $this->addItem($name, $item);
        }
    }

    public function addItem($name, $rule)
    {
        if (strpos($rule, ':') === false) {
            $operate = $rule;
            $arg = '';
        } else {
            [$operate, $arg] = explode(':', $rule);
        }
        if (!in_array($operate, $this->operations)) {
            throw new RuntimeException('检查操作' . $operate . '不存在');
        }
        $args = explode(',', $arg);
        $this->items[] = [
            'name' => $name,
            'operate' => $operate,
            'args' => $args
        ];
    }

    public function check()
    {
        $resultList = [];
        foreach ($this->items as $item) {
            $result = call_user_func_array([$this, $item['operate']], $item['args']);
            $resultList[] = [
                'name' => $item['name'],
                'result' => $result,
            ];
        }
        return $resultList;
    }

    public function func_exist($name)
    {
        return function_exists($name);
    }

    public function class_exist($name)
    {
        return class_exists($name);
    }

    public function ext_exist($name)
    {
        return extension_loaded($name);
    }

    public function file_exist($path)
    {
        $path = self::resolvePath($path);
        return file_exists($path);
    }

    public function can_read($path)
    {
        $path = self::resolvePath($path);
        if (!file_exists($path)) {
            return false;
        }
        if (@file_get_contents($path) === false) {
            return false;
        }
        return true;
    }

    public function can_write($path)
    {
        $path = self::resolvePath($path);
        if (file_exists($path)) {
            @unlink($path);
        }
        if (@file_put_contents($path, 'test') === false) {
            return false;
        }
        if (@unlink($path) === false) {
            return false;
        }
        return true;
    }

    public function db()
    {
        try {
            db()->getConnection()->getTables('');
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    public function resolvePath($path)
    {
        return preg_replace('/^@\//', env('root_path'), $path);;
    }
}
